package com.xiaoshuidi.cloud.module.contract.controller.admin.bill;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.OrderDetailVo;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.OrderResp;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.orderFees.OrderFeesCreateReqVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.orderFees.OrderFeesVo;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.rentOrder.RentOrderVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.Booking;
import com.xiaoshuidi.cloud.module.contract.enums.ApiConstants;
import com.xiaoshuidi.cloud.module.contract.enums.bill.*;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractRentCollectionTypeEnum;
import com.xiaoshuidi.cloud.module.contract.service.bill.dto.ContractOwnerFreePeriodDTO;
import com.xiaoshuidi.cloud.module.contract.service.contract.dto.OwnerContractRentOrderDTO;
import com.xiaoshuidi.cloud.module.contract.service.contract.dto.RentFreePeriodDTO;
import com.xiaoshuidi.cloud.module.contract.util.bill.BillPeriod;
import com.xiaoshuidi.cloud.module.contract.util.bill.DayRent;
import com.xiaoshuidi.cloud.module.contract.util.date.DateEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.web.bind.annotation.RequestBody;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.time.LocalDate;


import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.xiaoshuidi.cloud.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants.*;
import static com.xiaoshuidi.cloud.module.contract.util.bill.BillPeriod.splitByMonth;
import static com.xiaoshuidi.cloud.module.contract.util.bill.BillPeriod.splitByNaturalMonth;

import static com.xiaoshuidi.cloud.module.contract.util.bill.BillPeriod.*;

@Slf4j
public class DateRangeGenerator {

    // 根据账单 计算账单金额
    public static OrderResp calculateBillAmount(RentOrderVO rentOrderVO) {
        OrderResp orderResp=new OrderResp();
        LocalDate contractStartDate = rentOrderVO.getStartTime();
        LocalDate contractEndDate = rentOrderVO.getEndTime();
        BigDecimal monthRent = rentOrderVO.getMonthRent();
        //账单集合
        List<BillPeriod> billPeriods = splitByMonth(contractStartDate, contractEndDate, rentOrderVO.getPayMethodF());
        //已收金额
        BigDecimal residueAmount = rentOrderVO.getPaidRentUtilities()==null?BigDecimal.ZERO:rentOrderVO.getPaidRentUtilities();
        //减去抵押后的金额
        BigDecimal residue=rentOrderVO.getPaidRentUtilities()==null?BigDecimal.ZERO:rentOrderVO.getPaidRentUtilities();
        List<OrderDetailVo> orderDetailVos = new ArrayList<>();
        BigDecimal oldDeposit = rentOrderVO.getOldDeposit();

        List<JSONObject> rentFreePeriodDay = new ArrayList<>();
        //查看时间节点
        if(rentOrderVO.getRentFreePeriod() != null && rentOrderVO.getRentFreePeriod() == 1)
            rentFreePeriodDay = JSONUtil.toList(rentOrderVO.getRentFreePeriodDay(),JSONObject.class);

        //免租期
        BigDecimal totalFreeOfRent = new BigDecimal(0);
        for (BillPeriod billPeriod : billPeriods) {
            //计算租金
            BigDecimal totalRent = calculateRent(rentOrderVO, monthRent, billPeriod);
            //查询免租期
            JSONObject param = rentFreeTime(rentOrderVO,rentFreePeriodDay,billPeriod.getStartTime(), billPeriod.getEndTime(),totalRent,totalFreeOfRent);
            totalRent = param.getBigDecimal("totalRent");
            totalFreeOfRent = param.getBigDecimal("totalFreeOfRent");

            //计算物业费
            BigDecimal totalProperty = calculateRent(rentOrderVO, rentOrderVO.getProperty(), billPeriod);
            //优惠
            BigDecimal discount = getDiscount(rentOrderVO, monthRent, billPeriod);
            if (totalRent.compareTo(discount)<0) {
                throw exception(ORDER_AMOUNT);
            }
            //账单明细 集合
            List<OrderFeesCreateReqVO> feeDetailList = new ArrayList<>();

            BigDecimal bookingDeposit;
            //押金
            BigDecimal depositAmount = BigDecimal.ZERO;
            if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                depositAmount = rentOrderVO.getDeposit();
                Booking booking = rentOrderVO.getBooking();
                if(booking !=null){
                    if (BookingPayEnum.UNPAID.getCode().equals(booking.getPaymentStatus())
                            ||BookingPayEnum.PART.getCode().equals(booking.getPaymentStatus())) {
                        throw exception(BOOKING_NO_PAYMENT);
                    }
                    bookingDeposit = booking.getBookingDeposit()==null?BigDecimal.ZERO:booking.getBookingDeposit();
                    oldDeposit=oldDeposit.add(bookingDeposit);
                }
                //已付押金金额
                BigDecimal depositPaidAmount;
                if(residue.compareTo(depositAmount)>0){
                    depositPaidAmount=depositAmount;
                    residue=residue.subtract(depositAmount);
                }else {
                    depositPaidAmount=residue;
                    residue=BigDecimal.ZERO;
                }
                //押金账单 明细
                OrderFeesCreateReqVO deposit = addFeeDetail(depositAmount,depositPaidAmount, monthRent, BigDecimal.ZERO, billPeriod,
                        ApiConstants.DEPOSIT_FEE_ID, ApiConstants.DEPOSIT_FEE_NAME, OrderFeeSortTypeEnum.DEPOSIT.getCode());
                feeDetailList.add(deposit);
                orderResp.setTotalOldDepositAmount(oldDeposit);
                orderResp.setTotalDepositAmount(rentOrderVO.getDeposit());
            }
            //已付租金金额
            BigDecimal paidAmount=BigDecimal.ZERO;
            if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                if(residue.compareTo(totalRent)>0){
                    paidAmount=totalRent;
                    residue=residue.subtract(totalRent);
                }else {
                    paidAmount=residue;
                    residue=BigDecimal.ZERO;
                }
            }
            //添加租金明细
            OrderFeesCreateReqVO rent = addFeeDetail(totalRent,paidAmount, monthRent, discount, billPeriod, ApiConstants.RENT_FEE_ID, ApiConstants.RENT_FEE_NAME, OrderFeeSortTypeEnum.CYCLE.getCode());
            feeDetailList.add(rent);

            BigDecimal propertyPaidAmount=BigDecimal.ZERO;
            if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                //已付物业费金额
                if (residue.compareTo(depositAmount) > 0) {
                    propertyPaidAmount = depositAmount;
                    residue = residue.subtract(depositAmount);
                } else {
                    propertyPaidAmount = residue;
                    residue = BigDecimal.ZERO;
                }
            }
            //添加物业费明细
            OrderFeesCreateReqVO property = addFeeDetail(totalProperty,propertyPaidAmount,  rentOrderVO.getProperty(), BigDecimal.ZERO, billPeriod,
                    ApiConstants.PROPERTY_FEE_ID, ApiConstants.PROPERTY_FEE_NAME, OrderFeeSortTypeEnum.CYCLE.getCode());
            feeDetailList.add(property);
            //杂费账单 明细
            List<OrderFeesVo> orderFeesVo = rentOrderVO.getOrderFeesVo();
            BigDecimal extrasAmount = BigDecimal.ZERO;
            if (CollectionUtil.isNotEmpty(orderFeesVo)) {
                for (OrderFeesVo item : orderFeesVo) {
                    //一次性杂费 都计入首期账单
                    BigDecimal feeAmount = item.getFeeAmount() == null ? BigDecimal.ZERO : item.getFeeAmount();

                    if (OrderFeeSortTypeEnum.ONCE.getCode().equals(item.getFeeSort())
                            && contractStartDate.equals(billPeriod.getStartTime())) {
                        //已付一次杂费金额
                        BigDecimal onePaidAmount=BigDecimal.ZERO;
                        if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                            if (residue.compareTo(depositAmount) > 0) {
                                onePaidAmount = depositAmount;
                                residue = residue.subtract(depositAmount);
                            } else {
                                onePaidAmount = residue;
                                residue = BigDecimal.ZERO;
                            }
                        }
                        OrderFeesCreateReqVO once = addFeeDetail(feeAmount,onePaidAmount, feeAmount, BigDecimal.ZERO, billPeriod,
                                item.getFeeId(), item.getFeeName(), OrderFeeSortTypeEnum.ONCE.getCode());
                        feeDetailList.add(once);
                        extrasAmount = extrasAmount.add(feeAmount);
                        log.info("一次性费用：{}", feeAmount);
                    }

                    if (OrderFeeSortTypeEnum.DEPOSIT.getCode().equals(item.getFeeSort())
                            && contractStartDate.equals(billPeriod.getStartTime())) {
                        //已付押金金额
                        BigDecimal depositPaidAmount=BigDecimal.ZERO;
                        if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                            if (residue.compareTo(depositAmount) > 0) {
                                depositPaidAmount = depositAmount;
                                residue = residue.subtract(depositAmount);
                            } else {
                                depositPaidAmount = residue;
                                residue = BigDecimal.ZERO;
                            }
                        }
                        OrderFeesCreateReqVO once = addFeeDetail(feeAmount,depositPaidAmount, feeAmount, BigDecimal.ZERO, billPeriod,
                                item.getFeeId(), item.getFeeName(), OrderFeeSortTypeEnum.DEPOSIT.getCode());
                        feeDetailList.add(once);
                        extrasAmount = extrasAmount.add(feeAmount);
                        log.info("杂费费用：{}", feeAmount);
                    }

                    if (OrderFeeSortTypeEnum.CYCLE.getCode().equals(item.getFeeSort())) {
                        //整月杂费
                        BigDecimal totalCycle = billPeriod.totalFee(feeAmount);
                        //已付押金金额
                        BigDecimal cyclePaidAmount=BigDecimal.ZERO;
                        if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                            if (residue.compareTo(depositAmount) > 0) {
                                cyclePaidAmount = depositAmount;
                                residue = residue.subtract(depositAmount);
                            } else {
                                cyclePaidAmount = residue;
                                residue = BigDecimal.ZERO;
                            }
                        }
                        OrderFeesCreateReqVO cycle = addFeeDetail(totalCycle,cyclePaidAmount,feeAmount, BigDecimal.ZERO, billPeriod,
                                item.getFeeId(), item.getFeeName(), OrderFeeSortTypeEnum.CYCLE.getCode());
                        log.info("周期性费用：{}", totalCycle);
                        feeDetailList.add(cycle);
                        extrasAmount = extrasAmount.add(totalCycle);
                    }
                }
            }

            LocalDate receivablesTime = billPeriod.getStartTime();
            //收款日期
            if (ContractRentCollectionTypeEnum.ADVANCED.getCode().equals(rentOrderVO.getRentPayWay())) {
                receivablesTime = receivablesTime.minusDays(rentOrderVO.getAdvancedDays());
            } else if (ContractRentCollectionTypeEnum.FIXED.getCode().equals(rentOrderVO.getRentPayWay())) {
                receivablesTime = LocalDate.of(receivablesTime.getYear(), receivablesTime.getMonth(), rentOrderVO.getAdvancedDays());
            } else {
                receivablesTime = receivablesTime.minusMonths(1);
                receivablesTime = LocalDate.of(receivablesTime.getYear(), receivablesTime.getMonth(), rentOrderVO.getAdvancedDays());
            }
            //开始
            if(receivablesTime.isBefore(LocalDate.now())){
                receivablesTime=LocalDate.now();
            }
            BigDecimal totalAmount = totalRent.add(totalProperty).add(depositAmount).add(extrasAmount).subtract(discount);
            BigDecimal paidRentUtilities=BigDecimal.ZERO;
            String payStatus=OrderPayStatusEnum.UNPAID.getCode();
            if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                if(residueAmount.compareTo(totalAmount)<0){
                    paidRentUtilities=residueAmount;
                    payStatus=OrderPayStatusEnum.PART.getCode();
                }else {
                    paidRentUtilities=totalAmount;
                    payStatus=OrderPayStatusEnum.PAID.getCode();
                }
            }
            if(residueAmount.compareTo(BigDecimal.ZERO)==0){
                payStatus=OrderPayStatusEnum.UNPAID.getCode();
            }
            OrderDetailVo orderDetailVo = OrderDetailVo.builder()
                    .startTime(billPeriod.getStartTime())
                    .endTime(billPeriod.getEndTime())
                    .rentAmount(totalRent)
                    .depositAmount(depositAmount)
                    .extrasAmount(extrasAmount.add(totalProperty))
                    .oldDepositAmount(oldDeposit)
                    .discountValue(discount)
                    .extraDiscountValue(BigDecimal.ZERO)
                    .totalAmount(totalAmount)
                    .receivablesTime(receivablesTime)
                    .feeDetail(feeDetailList)
                    .paidRentUtilities(paidRentUtilities)
                    .payStatus(payStatus)
                    .build();
            orderDetailVos.add(orderDetailVo);

            orderResp.setTotalRent(orderResp.getTotalRent().add(totalRent));
            orderResp.setProperty(orderResp.getProperty().add(totalProperty));

            orderResp.setTotalFeesAmount(orderResp.getTotalFeesAmount().add(extrasAmount).add(totalProperty));
            orderResp.setTotalDiscountValue(orderResp.getTotalDiscountValue().add(discount));
            orderResp.setTotalFreeOfRent(totalFreeOfRent.setScale(2,BigDecimal.ROUND_HALF_UP));

            orderResp.setTotalAmount(orderResp.getTotalRent()
                    .add(orderResp.getTotalFeesAmount())
                    .add(orderResp.getTotalDepositAmount())
                    .subtract(orderResp.getTotalDiscountValue())
            );
            orderResp.setOrderDetailVos(orderDetailVos);
        }
        return orderResp;
    }


    /**
     * 查询时间
     * @param startTime
     * @param endTime
     * @return
     */
    private static JSONObject rentFreeTime(RentOrderVO rentOrderVO, List<JSONObject> rentFreePeriodDay,LocalDate startTime, LocalDate endTime,BigDecimal totalRent,BigDecimal totalFreeOfRent){
        JSONObject jsonObject = new JSONObject();
        jsonObject.putOpt("totalFreeOfRent",totalFreeOfRent);
        jsonObject.putOpt("totalRent",totalRent);
        if(rentOrderVO.getRentFreePeriod() == null || rentOrderVO.getRentFreePeriod() == 0)
            return jsonObject;

        BillPeriod.MonthAndRemainder m = new BillPeriod.MonthAndRemainder(startTime, endTime);
        //时间戳
        long start = startTime.atStartOfDay().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        long end = endTime.atStartOfDay().toInstant(ZoneOffset.of("+8")).toEpochMilli();

        //当月天数
        long day = startTime.until(endTime, ChronoUnit.DAYS) + 1;;
        long calculateDay = 0;
        for (JSONObject parm:rentFreePeriodDay) {
            //查看时间是否存在交集
            if(!( parm.getLong("endTime") < start ||  parm.getLong("startTime") > end)){
                //查询扣除金额
                //查找时间区间
                LocalDate calculateStartTime = LocalDate.from(LocalDateTime.ofInstant(Instant.ofEpochMilli(parm.getLong("startTime")), ZoneId.systemDefault()));
                LocalDate calculateEndTime = LocalDate.from(LocalDateTime.ofInstant(Instant.ofEpochMilli(parm.getLong("endTime")), ZoneId.systemDefault()));
                if (parm.getLong("startTime") < start)
                    calculateStartTime = startTime;

                if(parm.getLong("endTime") > end)
                    calculateEndTime = endTime;
                //计算租金
                //每日租金
                calculateDay = calculateDay + calculateStartTime.until(calculateEndTime, ChronoUnit.DAYS) + 1;
            }
        }
        //全免
        if(day == calculateDay){
            totalFreeOfRent = totalFreeOfRent.add(totalRent);
            totalRent =  new BigDecimal(0);
        } else if(0 == calculateDay){
            return jsonObject;
        }else{
            //当月免租金
            BigDecimal freeOfRent = totalRent.divide(new BigDecimal(day), 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal(calculateDay));
            totalFreeOfRent = totalFreeOfRent.add(freeOfRent);
            totalRent = totalRent.subtract(freeOfRent).setScale( 2, RoundingMode.HALF_UP);
        }
        jsonObject.putOpt("totalFreeOfRent",totalFreeOfRent);
        jsonObject.putOpt("totalRent",totalRent);
        return jsonObject;
    }

    /**
     * 计算免租金额
     * @param startTime
     * @param endTime
     * @param monthAmount
     * @return
     */
    private static BigDecimal calculate(LocalDate startTime, LocalDate endTime,BigDecimal monthAmount){
        BillPeriod.MonthAndRemainder m = new BillPeriod.MonthAndRemainder(startTime, endTime);
        BigDecimal total = monthAmount.multiply(BigDecimal.valueOf(m.getMonth()));
        // 生成合同账单计算金额时, 当二月在合同时间中间时(非首月), 账单结束日期是结束日期所在月份的最后一天, 这个账单在这里会余几天出来
        // 当生成账单时, 账单开始时间不是二月最后一天且有余数时, 余数天数是小于1个月几天, 这里直接算做一个月
        if (m.getRemainder() >= endTime.withMonth(2).lengthOfMonth()) {
            return total.add(monthAmount);
        }
        // 非完整账单计算金额时, 按实际月份和余数计算金额
        if (m.getMonth() == 0) {
            return monthAmount.multiply(BigDecimal.valueOf(totalDays(startTime, endTime)))
                    .divide(BigDecimal.valueOf(startTime.lengthOfMonth()), 2, RoundingMode.HALF_UP);
        }
        LocalDate remindStart = monthBillEndDate(startTime, m.isFebruaryIn(), m.getMonth(), endTime).plusDays(1);
        if (remindStart.isAfter(endTime)) {
            return total;
        }
        int lengthOfMonth = remindStart.lengthOfMonth();
        total = total.add(monthAmount.multiply(BigDecimal.valueOf(totalDays(remindStart, endTime)))
                .divide(BigDecimal.valueOf(lengthOfMonth), 2, RoundingMode.HALF_UP));
        return total;
    }


    @NotNull
    private static BigDecimal calculateRent(RentOrderVO rentOrderVO, BigDecimal monthRent, BillPeriod billPeriod) {
        //账单 整月总租金
        return billPeriod.totalFee(monthRent);
    }


    @NotNull
    private static BigDecimal calculateNaturalFirstRent(RentOrderVO rentOrderVO, BigDecimal monthRent, BillPeriod billPeriod) {
        BillPeriod.MonthAndRemainder mr = new BillPeriod.MonthAndRemainder(billPeriod.getStartTime(), billPeriod.getEndTime());
        if (billPeriod.isWholeMonth()){
            Integer payMethodF = rentOrderVO.getPayMethodF();
            return monthRent.multiply(new BigDecimal(mr.getMonth() * payMethodF));
        }
        // 开始时间月底
        LocalDate startMonthEndDay = billPeriod.getStartTime().withDayOfMonth(billPeriod.getStartTime().lengthOfMonth());
        long firstMonthDays = ChronoUnit.DAYS.between(billPeriod.getStartTime(), startMonthEndDay) + 1;
        // 合同结束时间月初
        LocalDate contractEndMonthFirstDay = rentOrderVO.getEndTime().withDayOfMonth(1);
        long endMonthDays = ChronoUnit.DAYS.between(contractEndMonthFirstDay, rentOrderVO.getEndTime()) + 1;
        // 日租金 = 月租金/（合同开始月合同天数 + 合同结束月合同天数）
        // 合同开始月租金 日租金*开始月天数
        BigDecimal firstMonthRent = (monthRent.divide(BigDecimal.valueOf(firstMonthDays + endMonthDays),4,BigDecimal.ROUND_HALF_UP)).multiply(BigDecimal.valueOf(firstMonthDays));
        if (mr.getMonth() > 0){
            firstMonthRent.add(monthRent.multiply(BigDecimal.valueOf(mr.getMonth())));
        }
        return firstMonthRent.setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    /*
     * 账单明细
     * */
    private static OrderFeesCreateReqVO addFeeDetail(BigDecimal totalRent, BigDecimal paidAmount, BigDecimal monthRent, BigDecimal discount, BillPeriod billPeriod , Long feeId, String feeName,String feeSort) {
        //租金账单 明细
        OrderFeesCreateReqVO feeDetail = new OrderFeesCreateReqVO();
        feeDetail.setFeeSort(feeSort);
        feeDetail.setFeeId(feeId);
        feeDetail.setFeeName(feeName);
        feeDetail.setAmount(totalRent);
        feeDetail.setPaidAmount(paidAmount);
        feeDetail.setFeeMonth(monthRent);
        feeDetail.setStartTime(billPeriod.getStartTime());
        feeDetail.setEndTime(billPeriod.getEndTime());
        feeDetail.setDiscountAmount(discount);
        feeDetail.setInvoiceStatus(0);
        return feeDetail;
    }


    public static BigDecimal getExtraDiscount(@RequestBody RentOrderVO rentOrderVO,
                                              LocalDate startDate, LocalDate endDate, OrderDetailVo range,
                                              LocalDate billStartDate, LocalDate billEndDate,
                                              DateEntity dateEntity) {
        if (OrderFeeSortTypeEnum.ONCE.getCode().equals(rentOrderVO.getExtraDiscountSort())) {
            if ("first".equals(rentOrderVO.getExtraDiscountOrder())) {
                if (startDate.compareTo(billStartDate) == 0) {
                    range.setExtraDiscountValue(rentOrderVO.getExtraDiscountValue());
                    return rentOrderVO.getExtraDiscountValue();
                } else if (endDate.compareTo(billEndDate) == 0) {
                    range.setExtraDiscountValue(rentOrderVO.getExtraDiscountValue());
                    return rentOrderVO.getExtraDiscountValue();
                }
            }
        } else if (OrderFeeSortTypeEnum.CYCLE.getCode().equals(rentOrderVO.getExtraDiscountSort())) {
            // 按账期（order）,按月租金(rent)
            if ("order".equals(rentOrderVO.getExtraDiscountType())) {
                range.setExtraDiscountValue(rentOrderVO.getExtraDiscountValue());
                return rentOrderVO.getExtraDiscountValue();
            } else if ("rent".equals(rentOrderVO.getExtraDiscountType())) {
                int yearMonth = dateEntity.getMonth() + dateEntity.getYear() * 12;
                if (dateEntity.getDay() > 0) {
                    yearMonth += 1;
                }
                BigDecimal billAmount = rentOrderVO.getExtraDiscountValue().multiply(BigDecimal.valueOf(yearMonth));
                range.setExtraDiscountValue(billAmount);
                return billAmount;
            }
        }
        return BigDecimal.ZERO;
    }

    public static BigDecimal getDiscount(@RequestBody RentOrderVO rentOrderVO, BigDecimal monthRent, BillPeriod billPeriod) {
        LocalDate billStartDate = billPeriod.getStartTime();
        LocalDate billEndDate = billPeriod.getEndTime();
        LocalDate contractStartDate = rentOrderVO.getStartTime();
        LocalDate contractEndDate = rentOrderVO.getEndTime();
        // 优惠折扣 一次性优惠
        BigDecimal oneDiscount = BigDecimal.ZERO;
        if (OrderFeeSortTypeEnum.ONCE.getCode().equals(rentOrderVO.getDiscountSort())) {
            if (OrderDiscountEnum.FIRST.getCode().equals(rentOrderVO.getDiscountOrder())
                    && contractStartDate.isEqual(billStartDate)) {
                if(rentOrderVO.getDiscountValue()!=null){
                    oneDiscount = rentOrderVO.getDiscountValue();
                }
            }
            if (OrderDiscountEnum.LAST.getCode().equals(rentOrderVO.getDiscountOrder())
                    && contractEndDate.equals(billEndDate)) {
                if(rentOrderVO.getDiscountValue()!=null){
                    oneDiscount = rentOrderVO.getDiscountValue();
                }
            }
        }
        //优惠折扣 周期性优惠
        BigDecimal cycleDiscount = BigDecimal.ZERO;
        if (OrderFeeSortTypeEnum.CYCLE.getCode().equals(rentOrderVO.getDiscountSort())) {
            //优惠金额
            if (OrderDiscountEnum.AMOUNT.getCode().equals(rentOrderVO.getDiscountType())) {
                if (rentOrderVO.getDiscountValue() != null) {
                    cycleDiscount = rentOrderVO.getDiscountValue();
                }
            }
            //百分比优惠
            if (OrderDiscountEnum.RATE.getCode().equals(rentOrderVO.getDiscountType())) {
                if (rentOrderVO.getDiscountValue() != null) {
                    BigDecimal rate = rentOrderVO.getDiscountValue().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
                    BigDecimal totalRent = billPeriod.totalFee(monthRent);
                    cycleDiscount = totalRent.multiply(rate).setScale(2, RoundingMode.HALF_UP);
                }
            }
        }

        return oneDiscount.add(cycleDiscount);
    }

    /**
     * 业主合同账单计算
     */
    public static OrderResp calculateOwnerBillAmount(OwnerContractRentOrderDTO rentOrder) {
        LocalDate contractStartDate = rentOrder.getStartTime();
        LocalDate contractEndDate = rentOrder.getEndTime();
        //账单周期
        List<BillPeriod> billPeriods = splitByMonth(contractStartDate, contractEndDate, rentOrder.getMonth());
        //免租金的账单周期
        List<ContractOwnerFreePeriodDTO> ownerFreePeriods = getOwnerFreePeriods(rentOrder, billPeriods);
        BigDecimal monthRent = rentOrder.getMonthRent();
        List<OrderDetailVo> orderDetailVos = new ArrayList<>();
        OrderResp orderResp = new OrderResp();
        for (BillPeriod billPeriod : billPeriods) {
            LocalDate billStartDate = billPeriod.getStartTime();
            LocalDate billEndDate = billPeriod.getEndTime();
            BigDecimal oldDeposit = rentOrder.getOldDepositAmount();
            //计算租金
            BigDecimal totalRent = calculateRent(null, monthRent, billPeriod);

            //免租期折扣
            BigDecimal discount = BigDecimal.ZERO;
            if (CollectionUtils.isNotEmpty(ownerFreePeriods)){
                ContractOwnerFreePeriodDTO freePeriodDTO = ownerFreePeriods.stream().filter(p -> p.getStartTime().equals(billPeriod.getStartTime())).findFirst().orElse(null);
                if (Objects.nonNull(freePeriodDTO)){
                    discount = monthRent.multiply(new BigDecimal(freePeriodDTO.getFreeMonthNum()));
                    if (discount.compareTo(totalRent) >= 0){
                        discount = totalRent;
                    }
                    ownerFreePeriods.remove(freePeriodDTO);
                }
            }

            //账单明细 集合
            List<OrderFeesCreateReqVO> feeDetailList = new ArrayList<>();
            //添加租金明细
            OrderFeesCreateReqVO rentDetail = new OrderFeesCreateReqVO();
            rentDetail.setFeeId(ApiConstants.RENT_FEE_ID);
            rentDetail.setFeeName(ApiConstants.RENT_FEE_NAME);
            rentDetail.setAmount(totalRent);
            rentDetail.setFeeMonth(monthRent);
            rentDetail.setStartTime(billStartDate);
            rentDetail.setEndTime(billEndDate);
            rentDetail.setDiscountAmount(discount);
            rentDetail.setFlowType(OrderFeeFlowTypeEnum.OUTFLOW.getCode());
            rentDetail.setOrderType(OrderTypeEnum.OWNER.getCode());
            rentDetail.setFeeSort(OrderFeeSortTypeEnum.CYCLE.getCode());
            feeDetailList.add(rentDetail);


            orderResp.setTotalRent(orderResp.getTotalRent().add(totalRent));
            orderResp.setTotalDiscountValue(orderResp.getTotalDiscountValue().add(discount));
            //押金
            BigDecimal depositAmount = BigDecimal.ZERO;
            if (billStartDate.isEqual(contractStartDate)) {
                depositAmount = rentOrder.getDepositAmount();
                //押金账单 明细
                OrderFeesCreateReqVO despositDetail = new OrderFeesCreateReqVO();
                despositDetail.setFeeId(ApiConstants.DEPOSIT_FEE_ID);
                despositDetail.setFeeName(ApiConstants.DEPOSIT_FEE_NAME);
                despositDetail.setAmount(depositAmount);
                despositDetail.setFeeMonth(monthRent);
                despositDetail.setStartTime(billStartDate);
                despositDetail.setEndTime(billEndDate);
                despositDetail.setDiscountAmount(BigDecimal.ZERO);
                despositDetail.setFlowType(OrderFeeFlowTypeEnum.OUTFLOW.getCode());
                despositDetail.setOrderType(OrderTypeEnum.OWNER.getCode());
                despositDetail.setFeeSort(OrderFeeSortTypeEnum.DEPOSIT.getCode());
                feeDetailList.add(despositDetail);
                orderResp.setTotalDepositAmount(rentOrder.getDepositAmount());
            }

            LocalDate receivablesTime = billPeriod.getStartTime();
            //收款日期
            if (ContractRentCollectionTypeEnum.ADVANCED.getCode().equals(rentOrder.getRentPayWay())) {
                receivablesTime = receivablesTime.minusDays(rentOrder.getAdvancedDays());
            } else if (ContractRentCollectionTypeEnum.FIXED.getCode().equals(rentOrder.getRentPayWay())) {
                receivablesTime = LocalDate.of(receivablesTime.getYear(), receivablesTime.getMonth(), rentOrder.getAdvancedDays());
            } else {
                receivablesTime = receivablesTime.minusMonths(1);
                receivablesTime = LocalDate.of(receivablesTime.getYear(), receivablesTime.getMonth(), rentOrder.getAdvancedDays());
            }
            //开始
            if(receivablesTime.isBefore(LocalDate.now())){
                receivablesTime=LocalDate.now();
            }
            OrderDetailVo orderDetailVo = OrderDetailVo.builder()
                    .startTime(billPeriod.getStartTime())
                    .endTime(billPeriod.getEndTime())
                    .rentAmount(totalRent)
                    .depositAmount(depositAmount)
                    .oldDepositAmount(oldDeposit)
                    .discountValue(discount)
                    .extraDiscountValue(BigDecimal.ZERO)
                    .totalAmount(totalRent.add(depositAmount).subtract(discount))
                    .receivablesTime(receivablesTime)
                    .feeDetail(feeDetailList)
                    .build();
            orderDetailVos.add(orderDetailVo);
            orderResp.setTotalAmount(orderResp.getTotalRent().add(orderResp.getTotalDepositAmount())
                    .add(orderResp.getTotalExtraDiscountValue()).subtract(orderResp.getTotalDiscountValue()));
        }
        orderResp.setOrderDetailVos(orderDetailVos);
        return orderResp;
    }

    public static List<ContractOwnerFreePeriodDTO> getOwnerFreePeriods(OwnerContractRentOrderDTO ownerContractRentOrderDTO, List<BillPeriod> billPeriods){
        List<RentFreePeriodDTO> rentFreePeriod = ownerContractRentOrderDTO.getRentFreePeriod();
        List<ContractOwnerFreePeriodDTO> free = new ArrayList<>();
        for (RentFreePeriodDTO dto : rentFreePeriod) {
            int yearNo = dto.getYearNo() - 1;
            LocalDate startDate = ownerContractRentOrderDTO.getStartTime();
            if (yearNo > 0){
                startDate = startDate.plusYears(yearNo);
            }
            //向上取整
            int cycle = (int) Math.ceil((double)dto.getFreePeriodMonthNum() / ownerContractRentOrderDTO.getMonth());
            for (int i = 0; i < cycle; i++) {
                LocalDate finalStartDate = startDate;
                BillPeriod billPeriod = billPeriods.stream().filter(b -> b.getStartTime().equals(finalStartDate)).findFirst().orElse(null);
                if (Objects.nonNull(billPeriod)){
                    ContractOwnerFreePeriodDTO freePeriod = new ContractOwnerFreePeriodDTO();
                    freePeriod.setStartTime(billPeriod.getStartTime());
                    freePeriod.setEndTime(billPeriod.getEndTime());
                    Integer freeMonthNum = dto.getFreePeriodMonthNum();
                    if (cycle > 1){
                        if ((i + 1) < cycle){
                            freeMonthNum = ownerContractRentOrderDTO.getMonth();
                        }else {
                            if (1 == ownerContractRentOrderDTO.getMonth()){
                                freeMonthNum = 1;
                            }else {
                                freeMonthNum = dto.getFreePeriodMonthNum() % ownerContractRentOrderDTO.getMonth();
                            }
                        }
                    }
                    freePeriod.setFreeMonthNum(freeMonthNum);
                    free.add(freePeriod);
                    startDate = billPeriod.getEndTime().plusDays(1);
                }
            }
        }
        return free;
    }

//    public static void main(String[] args) {
//        RentOrderVO rentOrderVO = new RentOrderVO();
//        rentOrderVO.setDeposit(new BigDecimal("1000"));
//        rentOrderVO.setMonthRent(new BigDecimal("1000"));
//        rentOrderVO.setStartTime(LocalDate.of(2024,4,6));
//        rentOrderVO.setEndTime(LocalDate.of(2024,7,5));
//        rentOrderVO.setPayMethodF(1);
//        rentOrderVO.setPayMethodY(1);
//        rentOrderVO.setProperty(new BigDecimal("200"));
//        rentOrderVO.setRentPayWay("advanced");
//        rentOrderVO.setAdvancedDays(10);
//        rentOrderVO.setDiscountSort("cycle");
//        rentOrderVO.setDiscountOrder("first");
//        rentOrderVO.setDiscountType("amount");
//        rentOrderVO.setOldDeposit(new BigDecimal("0"));
//        rentOrderVO.setCustomerType("personal");
//
//        OrderResp orderResp = calculateNaturalMonthBillAmount(rentOrderVO);
//        System.out.println();
//    }

    /**
     * 计算自然月账单
     */
    public static OrderResp calculateNaturalMonthBillAmount(RentOrderVO rentOrderVO) {
        OrderResp orderResp=new OrderResp();
        LocalDate contractStartDate = rentOrderVO.getStartTime();
        LocalDate contractEndDate = rentOrderVO.getEndTime();
        BigDecimal monthRent = rentOrderVO.getMonthRent();
        //账单集合
        List<BillPeriod> billPeriods = splitByNaturalMonth(contractStartDate, contractEndDate, rentOrderVO.getPayMethodF());
        //已收金额
        BigDecimal residueAmount = rentOrderVO.getPaidRentUtilities()==null?BigDecimal.ZERO:rentOrderVO.getPaidRentUtilities();
        //减去抵押后的金额
        BigDecimal residue=rentOrderVO.getPaidRentUtilities()==null?BigDecimal.ZERO:rentOrderVO.getPaidRentUtilities();
        List<OrderDetailVo> orderDetailVos = new ArrayList<>();
        BigDecimal oldDeposit = rentOrderVO.getOldDeposit();

        BigDecimal firstMonthRent = BigDecimal.ZERO;
        BigDecimal firstMonthProperty = BigDecimal.ZERO;
        BigDecimal firstMonthCycleFee = BigDecimal.ZERO;
        BigDecimal totalProperty = BigDecimal.ZERO;
        for (BillPeriod billPeriod : billPeriods) {
            //计算租金
            BigDecimal totalRent;
            //账单明细 集合
            List<OrderFeesCreateReqVO> feeDetailList = new ArrayList<>();
            //押金
            BigDecimal depositAmount = BigDecimal.ZERO;
            if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                // 首期账单
                // 账单周期整月
                if (billPeriod.isCycleWholeMonth()){
                    totalRent = calculateNaturalFirstRent(rentOrderVO,monthRent,billPeriod);
                    firstMonthRent = totalRent;
                    //计算物业费
                    totalProperty = calculateNaturalFirstRent(rentOrderVO, rentOrderVO.getProperty(), billPeriod);
                }else {
                    totalRent = calculateRent(rentOrderVO, monthRent, billPeriod);
                    //计算物业费
                    totalProperty = calculateRent(rentOrderVO, rentOrderVO.getProperty(), billPeriod);
                }
                firstMonthProperty = totalProperty;
                depositAmount = rentOrderVO.getDeposit();
                Booking booking = rentOrderVO.getBooking();
                if(booking !=null){
                    // 有预定
                    if (BookingPayEnum.UNPAID.getCode().equals(booking.getPaymentStatus())
                            ||BookingPayEnum.PART.getCode().equals(booking.getPaymentStatus())) {
                        throw exception(BOOKING_NO_PAYMENT);
                    }
                    BigDecimal bookingDeposit = booking.getBookingDeposit()==null?BigDecimal.ZERO:booking.getBookingDeposit();
                    oldDeposit=oldDeposit.add(bookingDeposit);
                }
                //已付押金金额
                BigDecimal depositPaidAmount;
                if(residue.compareTo(depositAmount)>0){
                    depositPaidAmount=depositAmount;
                    residue=residue.subtract(depositAmount);
                }else {
                    depositPaidAmount=residue;
                    residue=BigDecimal.ZERO;
                }
                //押金账单 明细
                OrderFeesCreateReqVO deposit = addFeeDetail(depositAmount,depositPaidAmount, monthRent, BigDecimal.ZERO, billPeriod,
                        ApiConstants.DEPOSIT_FEE_ID, ApiConstants.DEPOSIT_FEE_NAME, OrderFeeSortTypeEnum.DEPOSIT.getCode());
                feeDetailList.add(deposit);
                orderResp.setTotalOldDepositAmount(oldDeposit);
                orderResp.setTotalDepositAmount(rentOrderVO.getDeposit());
            }else if (billPeriod.getEndTime().isEqual(contractEndDate)){
                // 末期账单
                if (billPeriod.isCycleWholeMonth() && !billPeriod.isWholeMonth()){
                    // 末期账单最后一个月账单 周期整月
                    // 月租金 - 首月租金
                    BigDecimal endMonthRent =  monthRent.subtract(firstMonthRent);
                    BillPeriod.MonthAndRemainder monthAndRemainder = new BillPeriod.MonthAndRemainder(billPeriod.getStartTime(), billPeriod.getEndTime());
                    // 租金 = 整月月份 * 月租金 + （月租金 - 首月租金）
                    totalRent = endMonthRent.add(monthRent.multiply(BigDecimal.valueOf(monthAndRemainder.getMonth())));
                    // 物业费同理
                    BigDecimal endMonthProperty =  rentOrderVO.getProperty().subtract(firstMonthProperty);
                    totalProperty = endMonthProperty.add(rentOrderVO.getProperty().multiply(BigDecimal.valueOf(monthAndRemainder.getMonth())));
                }else {
                    totalRent = calculateRent(rentOrderVO, monthRent, billPeriod);
                    //计算物业费
                    totalProperty = calculateRent(rentOrderVO, rentOrderVO.getProperty(), billPeriod);
                }
            }else {
                totalRent = calculateRent(rentOrderVO, monthRent, billPeriod);
                //计算物业费
                totalProperty = calculateRent(rentOrderVO, rentOrderVO.getProperty(), billPeriod);
            }

//            //计算物业费
//            totalProperty = calculateRent(rentOrderVO, rentOrderVO.getProperty(), billPeriod);
            //优惠
            BigDecimal discount = getDiscount(rentOrderVO, monthRent, billPeriod);
            // 折扣不能大于总租金
            if (totalRent.compareTo(discount)<=0) {
                throw exception(ORDER_AMOUNT);
            }
            //已付租金金额
            BigDecimal paidAmount=BigDecimal.ZERO;
            if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                if(residue.compareTo(totalRent)>0){
                    paidAmount=totalRent;
                    residue=residue.subtract(totalRent);
                }else {
                    paidAmount=residue;
                    residue=BigDecimal.ZERO;
                }
            }
            //添加租金明细
            OrderFeesCreateReqVO rent = addFeeDetail(totalRent,paidAmount, monthRent, discount, billPeriod, ApiConstants.RENT_FEE_ID, ApiConstants.RENT_FEE_NAME, OrderFeeSortTypeEnum.CYCLE.getCode());
            feeDetailList.add(rent);

            BigDecimal propertyPaidAmount=BigDecimal.ZERO;
            if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                //已付物业费金额
                if (residue.compareTo(depositAmount) > 0) {
                    propertyPaidAmount = depositAmount;
                    residue = residue.subtract(depositAmount);
                } else {
                    propertyPaidAmount = residue;
                    residue = BigDecimal.ZERO;
                }
            }
            //添加物业费明细
            OrderFeesCreateReqVO property = addFeeDetail(totalProperty,propertyPaidAmount,  rentOrderVO.getProperty(), BigDecimal.ZERO, billPeriod,
                    ApiConstants.PROPERTY_FEE_ID, ApiConstants.PROPERTY_FEE_NAME, OrderFeeSortTypeEnum.CYCLE.getCode());
            feeDetailList.add(property);
            //杂费账单 明细
            List<OrderFeesVo> orderFeesVo = rentOrderVO.getOrderFeesVo();
            BigDecimal extrasAmount = BigDecimal.ZERO;
            if (CollectionUtil.isNotEmpty(orderFeesVo)) {
                for (OrderFeesVo item : orderFeesVo) {
                    //一次性杂费 都计入首期账单
                    BigDecimal feeAmount = item.getFeeAmount() == null ? BigDecimal.ZERO : item.getFeeAmount();

                    if (OrderFeeSortTypeEnum.ONCE.getCode().equals(item.getFeeSort())
                            && contractStartDate.equals(billPeriod.getStartTime())) {
                        //已付一次杂费金额
                        BigDecimal onePaidAmount=BigDecimal.ZERO;
                        if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                            if (residue.compareTo(depositAmount) > 0) {
                                onePaidAmount = depositAmount;
                                residue = residue.subtract(depositAmount);
                            } else {
                                onePaidAmount = residue;
                                residue = BigDecimal.ZERO;
                            }
                        }
                        OrderFeesCreateReqVO once = addFeeDetail(feeAmount,onePaidAmount, feeAmount, BigDecimal.ZERO, billPeriod,
                                item.getFeeId(), item.getFeeName(), OrderFeeSortTypeEnum.ONCE.getCode());
                        feeDetailList.add(once);
                        extrasAmount = extrasAmount.add(feeAmount);
                        log.info("一次性费用：{}", feeAmount);
                    }

                    if (OrderFeeSortTypeEnum.DEPOSIT.getCode().equals(item.getFeeSort())
                            && contractStartDate.equals(billPeriod.getStartTime())) {
                        //已付押金金额
                        BigDecimal depositPaidAmount=BigDecimal.ZERO;
                        if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                            if (residue.compareTo(depositAmount) > 0) {
                                depositPaidAmount = depositAmount;
                                residue = residue.subtract(depositAmount);
                            } else {
                                depositPaidAmount = residue;
                                residue = BigDecimal.ZERO;
                            }
                        }
                        OrderFeesCreateReqVO once = addFeeDetail(feeAmount,depositPaidAmount, feeAmount, BigDecimal.ZERO, billPeriod,
                                item.getFeeId(), item.getFeeName(), OrderFeeSortTypeEnum.DEPOSIT.getCode());
                        feeDetailList.add(once);
                        extrasAmount = extrasAmount.add(feeAmount);
                        log.info("杂费费用：{}", feeAmount);
                    }

                    if (OrderFeeSortTypeEnum.CYCLE.getCode().equals(item.getFeeSort())) {
                        //整月杂费
                        BigDecimal totalCycle = billPeriod.totalFee(feeAmount);
                        if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                            firstMonthCycleFee = totalCycle;
                        }
                        if (billPeriod.getEndTime().isEqual(contractEndDate) && billPeriod.isCycleWholeMonth() && !billPeriod.isWholeMonth()){
                            BillPeriod.MonthAndRemainder monthAndRemainder = new BillPeriod.MonthAndRemainder(billPeriod.getStartTime(), billPeriod.getEndTime());
                            totalCycle = feeAmount.subtract(firstMonthCycleFee);
                            totalCycle = totalCycle.add(feeAmount.multiply(BigDecimal.valueOf(monthAndRemainder.getMonth())));
                        }
                        //已付押金金额
                        BigDecimal cyclePaidAmount=BigDecimal.ZERO;
                        if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                            if (residue.compareTo(depositAmount) > 0) {
                                cyclePaidAmount = depositAmount;
                                residue = residue.subtract(depositAmount);
                            } else {
                                cyclePaidAmount = residue;
                                residue = BigDecimal.ZERO;
                            }
                        }
                        OrderFeesCreateReqVO cycle = addFeeDetail(totalCycle,cyclePaidAmount,feeAmount, BigDecimal.ZERO, billPeriod,
                                item.getFeeId(), item.getFeeName(), OrderFeeSortTypeEnum.CYCLE.getCode());
                        log.info("周期性费用：{}", totalCycle);
                        feeDetailList.add(cycle);
                        extrasAmount = extrasAmount.add(totalCycle);
                    }
                }
            }

            LocalDate receivablesTime = billPeriod.getStartTime();
            //收款日期
            if (ContractRentCollectionTypeEnum.ADVANCED.getCode().equals(rentOrderVO.getRentPayWay())) {
                receivablesTime = receivablesTime.minusDays(rentOrderVO.getAdvancedDays());
            } else if (ContractRentCollectionTypeEnum.FIXED.getCode().equals(rentOrderVO.getRentPayWay())) {
                receivablesTime = LocalDate.of(receivablesTime.getYear(), receivablesTime.getMonth(), rentOrderVO.getAdvancedDays());
            } else {
                receivablesTime = receivablesTime.minusMonths(1);
                receivablesTime = LocalDate.of(receivablesTime.getYear(), receivablesTime.getMonth(), rentOrderVO.getAdvancedDays());
            }
            //开始
            if(receivablesTime.isBefore(LocalDate.now())){
                receivablesTime=LocalDate.now();
            }
            BigDecimal totalAmount = totalRent.add(totalProperty).add(depositAmount).add(extrasAmount).subtract(discount);
            BigDecimal paidRentUtilities=BigDecimal.ZERO;
            String payStatus=OrderPayStatusEnum.UNPAID.getCode();
            if (billPeriod.getStartTime().isEqual(contractStartDate)) {
                if(residueAmount.compareTo(totalAmount)<0){
                    paidRentUtilities=residueAmount;
                    payStatus=OrderPayStatusEnum.PART.getCode();
                }else {
                    paidRentUtilities=totalAmount;
                    payStatus=OrderPayStatusEnum.PAID.getCode();
                }
            }
            if(residueAmount.compareTo(BigDecimal.ZERO)==0){
                payStatus=OrderPayStatusEnum.UNPAID.getCode();
            }
            OrderDetailVo orderDetailVo = OrderDetailVo.builder()
                    .startTime(billPeriod.getStartTime())
                    .endTime(billPeriod.getEndTime())
                    .rentAmount(totalRent)
                    .depositAmount(depositAmount)
                    .extrasAmount(extrasAmount.add(totalProperty))
                    .oldDepositAmount(oldDeposit)
                    .discountValue(discount)
                    .extraDiscountValue(BigDecimal.ZERO)
                    .totalAmount(totalAmount)
                    .receivablesTime(receivablesTime)
                    .feeDetail(feeDetailList)
                    .paidRentUtilities(paidRentUtilities)
                    .payStatus(payStatus)
                    .build();
            orderDetailVos.add(orderDetailVo);

            orderResp.setTotalRent(orderResp.getTotalRent().add(totalRent));
            orderResp.setProperty(orderResp.getProperty().add(totalProperty));

            orderResp.setTotalFeesAmount(orderResp.getTotalFeesAmount().add(extrasAmount).add(totalProperty));
            orderResp.setTotalDiscountValue(orderResp.getTotalDiscountValue().add(discount));

            orderResp.setTotalAmount(orderResp.getTotalRent()
                    .add(orderResp.getTotalFeesAmount())
                    .add(orderResp.getTotalDepositAmount())
                    .subtract(orderResp.getTotalDiscountValue())
            );
            orderResp.setOrderDetailVos(orderDetailVos);
        }
        return orderResp;
    }

}
